<?php
namespace App\Model;

use \Nette\Utils\Strings,    
    App\Model\Dao\User,
    \Nette\Security\IAuthenticator,	
    \Nette\Security\AuthenticationException,	
    \Nette\Security\Identity,
    \Nette\Mail\Message,
    \Nette\Mail\SendmailMailer;

/**
 * User manager
 */
class UserManager extends \Nette\Object implements IAuthenticator{
  
  private $em;
  private $userDao;

  /**
   * init object
   * @param \Kdyby\Doctrine\EntityManager $em
   */
  public function __construct(\Kdyby\Doctrine\EntityManager $em){
    $this->em = $em;
    $this->userDao = $em->getDao(Dao\User::getClassName());
  }
  
  /**
   * Authenticate user
   * @param array $credentials
   * @return \Nette\Security\Identity
   * @throws AuthenticationException
   */
  public function authenticate(array $credentials) {
		list($login, $password) = $credentials;
		

    $user = $this->userDao->findOneBy(array('login' => $login));
    
    if (!$user) {
			throw new AuthenticationException('Přihlášení se nezdařilo');
		}
    
		if ($user->getPassword() !== self::getHashPassword($password, $user->getSalt())) {
			throw new AuthenticationException('Přihlašování se nezdařilo');
		}
    
    // User state
    $userStateName = $user->getUserstate()->getName();
    
    switch($userStateName){
      case 'no_active':
        throw new AuthenticationException('Učet není zatím aktivní, aktivujte jej nejprve');
        break;
      case 'blocked':
        throw new AuthenticationException('Učet byl zablokován');
        break;
      case 'deleted':
        throw new AuthenticationException('Učet byl vymazán');
        break;
    }
      
		// identity
		return new Identity($user->getId(), $user->getRole()->getName());
	}
  
  /**
   * Return all users
   * @return type
   */
  public function getAllUsers(){
    return $this->userDao->findAll();
  }
  
  /**
   * Is login populated or not
   * @param string $login
   * @return boolean
   */
  public function isLoginFree($login){
    $result = $this->userDao->findBy(array('login' => $login));

    if($result){
      return false;
    }
    
    return true;
  }
  
  /**
   * Is email populate or not
   * @param type $email
   * @return boolean
   */
  public function isEmailFree($email){
    $result = $this->userDao->findBy(array('email' => $email));

    if($result){
      return false;
    }
    
    return true;
  }
  
  /**
   * Comment count
   * @param User $user
   * @return int
   */
  public function getUsersVideoCommentCount($user){
    $commentDao = $this->em->getDao(Dao\VideoComment::getClassName());
    $count = $commentDao->countBy(array('user' => $user));
    
    return $count;
  }
  
  /**
   * View count
   * @param User $user
   * @return int
   */
  public function getUsersVideoViewCount($user){
    $viewDao = $this->em->getDao(Dao\VideoView::getClassName());
    $count = $viewDao->countBy(array('user' => $user));
    
    return $count;
  }
 
  /**
   * Create new user
   * @param string $login
   * @param string $password
   * @param string $email
   * @param Presenter $presenter
   */
  public function registerNewUser($login, $password, $email, $presenter){
    
    $role = $this->em->getDao(Dao\Role::getClassName())->findOneBy(array('name' => 'user'));
    $userstate = $this->em->getDao(Dao\UserState::getClassName())->findOneBy(array('name' => 'no_active'));
    $hashSalt = hash('sha512', Strings::random(10));
    $hashPassword = self::getHashPassword($password, $hashSalt);
    $registred = new \DateTime();
    $regcode = Strings::random(10);
    
    $newUser = new User();
    $newUser->setAll($role, $userstate, $login, $hashPassword, $hashSalt, $regcode, $registred, $email);
    
    $this->em->persist($newUser);
    $this->em->flush();
    
    // Send mail 
    $presenter->absoluteUrls = true;
    $url = $presenter->link('Homepage:activation', array('code' => $regcode));
    
    $text = 'Dobrý den,' . PHP_EOL . PHP_EOL;
    $text .= 'Registroval/a jste se na webu www.nanastroj.cz, posíláme Vám proto potvrzovací link. Na ten je potřeba kliknout'
        . ', aby se Váš účet úspěšně aktivoval. Navštivte proto tento odkaz:' . PHP_EOL . PHP_EOL;
    $text .= $url . ' ' . PHP_EOL;
    $text .= 'Také se mohlo stát, že Váš email někdo zadal při registraci omylem. V takovém případě se omlouváme za navyžádanou zprávau'
        . 'a přejeme Vám pěkný den.' . PHP_EOL . PHP_EOL;
    $text .= 'NaNastroj.cz - lekce kytary online';
    
    $mail = new Message;
    $mail->setFrom('info@nanastroj.cz')
      ->addTo($email)
      ->setSubject('Registrace nového uživatele - NaNastroj.cz')
      ->setBody($text);

    $mailer = new SendmailMailer;
    $mailer->send($mail);
  }
  
  /**
   * Change user data
   * @param string $userId
   * @param string $email
   * @param int $age
   * @param string $place
   * @param string $gear
   * @param string $about
   * @param string $level
   * @param string $gender
   * @param string $photo
   */
  public function changeUserInfo($userId, $email, $age, $place, $gear, $about, $level, $gender, $photo = NULL){
    $user = $this->getUserById($userId);
    $user->setEmail($email);
    $user->setAge($age);
    $user->setPlace($place);
    $user->setGear($gear);
    $user->setAbout($about);
    $user->setLevel($level);
    $user->setGender($gender);
    
    if($photo){
      $user->setPhoto($photo);
    }
    
    $this->em->persist($user);
    $this->em->flush();
  }
  
  /**
   * User by login
   * @param String $login
   * @return boolean
   */
  public function getUserIdByLogin($login){
    $user = $this->userDao->findOneBy(array('login' => $login));
    if($user){
      return $user->getId();
    }
    
    return false;
  }
  
  /**
   * User by email
   * @param string $email
   * @return boolean
   */
  public function getUserIdByEmail($email){
    $user = $this->userDao->findOneBy(array('email' => $email));
    
    if($user){
      return $user->id;
    }
    
    return false;
  }
  
  /**
   * User activation
   * @param String $activationCode
   * @return boolean
   */
  public function activateUser($activationCode){
    $user = $this->userDao->findOneBy(array('regcode' => $activationCode));

    if($user && $user->getUserstate()->getName() == 'no_active'){
      $userstate = $this->em->getDao(Dao\UserState::getClassName())->findOneBy(array('name' => 'active'));
      $user->setUserstate($userstate);
      $this->em->persist($user);
      $this->em->flush();
      
      return true;
    }
    
    return false;
  }
  
  /**
   * Change state of user
   * @param int $userId
   * @param String $newState
   * @return boolean
   */
  public function changeUserState($userId, $newState){
    $user = $this->getUserById($userId);
    $userstate = $this->em->getDao(Dao\UserState::getClassName())->findOneBy(array('name' => $newState));
    
    if($user && $userstate){
      $user->setUserstate($userstate);
      $this->em->persist($user);
      $this->em->flush();
      
      return true;
    }
    
    return false;
  }
  
  /**
   * Change password of user
   * @param User $user
   * @param String $newPassword
   * @return boolean
   */
  public function changePassword($user, $newPassword){
    
    if(!$user){
      return false;
    }
    
    $hashSalt = hash('sha512', Strings::random(10));
    $hashPassword = self::getHashPassword($newPassword, $hashSalt);
    
    $user->setSalt($hashSalt);
    $user->setPassword($hashPassword);
    
    $this->em->persist($user);
    $this->em->flush();
  }
  
  /**
   * Get user by id
   * @param int $id
   * @return User
   */
  public function getUserById($id){
    return $this->userDao->findOneBy(array('id' => $id));
  }
  
  /**
   * Hash password
   * @param String $password
   * @param String $salt
   * @return String
   */
  public static function getHashPassword($password, $salt){
		return hash('sha512', $password . $salt);
	}
  
  /**
   * Returns client's IP adress
   * @return string IP
   */
  public static function getUserIp() {
    $ipaddress = '';
    if (getenv('HTTP_CLIENT_IP')) {
      $ipaddress = getenv('HTTP_CLIENT_IP');
    } else if (getenv('HTTP_X_FORWARDED_FOR')) {
      $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
    } else if (getenv('HTTP_X_FORWARDED')) {
      $ipaddress = getenv('HTTP_X_FORWARDED');
    } else if (getenv('HTTP_FORWARDED_FOR')) {
      $ipaddress = getenv('HTTP_FORWARDED_FOR');
    } else if (getenv('HTTP_FORWARDED')) {
      $ipaddress = getenv('HTTP_FORWARDED');
    } else if (getenv('REMOTE_ADDR')) {
      $ipaddress = getenv('REMOTE_ADDR');
    } else {
      $ipaddress = 'unknown';
    }
    return $ipaddress;
  }
  
  /**
   * Get user DAO object
   * @return User
   */
  public function getUserDao(){
    return $this->userDao;
  }
  
  /**
   * Get user list array
   * @return array
   */
  public function getBasicUserListArray(){
    $qb = $this->em->createQueryBuilder()
        ->addSelect('u.login AS login')
        ->addSelect('u.email AS email')
        ->addSelect('r.name AS rolename')
        ->addSelect('us.name AS statename')
        ->from(Dao\User::getClassName(), ' u')
        ->innerJoin('u.role', 'r')
        ->innerJoin('u.userstate', 'us');
        
    
    return $qb->getQuery()->getArrayResult();
  }
}
